use crate::proc_macro::TokenStream;
use proc_macro;
use quote::quote;
use syn::{DeriveInput, ItemFn, parse_macro_input};

/// 派生宏（Derive Macros）
/// 使用场景：自动为类型实现 trait
/// 通过 #[derive(YourMacro)] 自动生成代码，减少重复样板代码。
/// 典型用例：
///    实现常用 trait：如 Debug、Clone、Serialize（serde 库）等。
///    自定义派生逻辑：为结构体/枚举生成领域特定代码（如 ORM 映射、协议编解码）。
///    标记 trait：通过派生宏添加元信息（如 #[derive(Component)] 在 ECS 框架中注册组件）。
#[proc_macro_derive(HelloMacroDerive)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
    // 将 Rust 代码解析为语法树以便进行操作
    let ast = parse_macro_input!(input as DeriveInput);
    // 获取结构体或枚举的名字
    let name = &ast.ident;

    // 构建 trait 实现
    let expanded = quote! {
        impl HelloMacro for #name {
            fn hello_macro() {
                println!("Hello, Macro! My name is {}", stringify!(#name));
            }
        }
    };

    // 返回生成的代码
    TokenStream::from(expanded)
}

///属性宏（Attribute Macros）
/// 使用场景：修改或扩展被标记的项
/// 通过 #[your_attr(...)] 附加到函数、结构体等上，修改其行为或生成新代码。
/// 典型用例：
///     Web 框架路由：如 Rocket 的 #[get("/")] 将函数转换为请求处理器。
///     测试框架：如 #\[test\] 或 #\[tokio::test\] 标记测试函数。
///     代码转换：生成 AOP 风格代码（如日志、性能监控）。
///     FFI 绑定：如 #\[wasm_bindgen\] 生成 WebAssembly 接口。
///     领域特定语言（DSL）：自定义语法（如状态机、配置解析）。
#[proc_macro_attribute]
pub fn my_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
    // 解析输入的函数
    let mut input_fn = parse_macro_input!(item as ItemFn);

    // 过滤掉当前宏属性,防止新生成的函数再次被当前宏处理
    // 这一步是为了避免递归调用，防止宏无限循环
    input_fn.attrs.retain(|attr| {
        // 检查属性路径是否不是当前宏
        !attr.path.is_ident("my_test")
    });

    // 获取函数的名称,例如：my_function
    let fn_name = &input_fn.sig.ident;
    let fn_vis = &input_fn.vis;
    // 获取函数的属性 (e.g., #[test])
    let fn_attrs = &input_fn.attrs;
    // 获取函数的签名,例如 fn signature, 这里的签名包括参数、返回类型等
    let fn_sig = &input_fn.sig;
    // 获取函数的代码块,例如 fn block
    let fn_block = &input_fn.block;

    // 生成新的代码
    let expanded = quote! {
        #(#fn_attrs)*
        #fn_vis #fn_sig {
            println!("Before calling {}", stringify!(#fn_name));

            // 执行原始函数体并捕获结果
            let __result = #fn_block;

            println!("After calling {}", stringify!(#fn_name));

            // 返回原始函数的结果
            __result
        }
    };

    // 将生成的代码转换回 TokenStream
    TokenStream::from(expanded)
}

///函数式宏（Function-like Macros）
///使用场景：类函数调用的代码生成
/// 通过 your_macro!(...) 调用，接受标记流（TokenStream）作为输入，生成任意代码。
/// 典型用例：
///     复杂代码模板：生成重复模式（如 vec![...] 初始化向量）。
///     嵌入式 SQL：如 sql!("SELECT * FROM table") 在编译时验证 SQL。
///     模式匹配增强：自定义 match 逻辑（如更强大的错误处理）。
///     编译时计算：基于输入生成常量表达式（如 CRC 表生成）。
#[proc_macro]
pub fn say_hello(_input: TokenStream) -> TokenStream {
    // 生成代码
    let expanded = quote! {
        println!("Hello, world!");
    };

    // 将生成的代码转换为 TokenStream
    TokenStream::from(expanded)
}
